use crate::HysteriaClient;
use std::sync::Arc;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream;
use tracing::{debug, warn};

pub async fn handle_socks5(
    mut socket: TcpStream,
    _client: Arc<HysteriaClient>,
) -> anyhow::Result<()> {
    // SOCKS5 handshake
    let mut buf = [0u8; 2];
    socket.read_exact(&mut buf).await?;

    if buf[0] != 0x05 {
        warn!("Invalid SOCKS version: {}", buf[0]);
        return Ok(());
    }

    let nmethods = buf[1] as usize;
    let mut methods = vec![0u8; nmethods];
    socket.read_exact(&mut methods).await?;

    // Reply: no authentication required
    socket.write_all(&[0x05, 0x00]).await?;

    // Read request
    let mut buf = [0u8; 4];
    socket.read_exact(&mut buf).await?;

    if buf[0] != 0x05 {
        return Ok(());
    }

    let cmd = buf[1];
    let atyp = buf[3];

    // Parse address
    let addr = match atyp {
        0x01 => {
            // IPv4
            let mut ip = [0u8; 4];
            socket.read_exact(&mut ip).await?;
            let mut port = [0u8; 2];
            socket.read_exact(&mut port).await?;
            format!("{}.{}.{}.{}:{}", ip[0], ip[1], ip[2], ip[3], u16::from_be_bytes(port))
        }
        0x03 => {
            // Domain
            let mut len = [0u8; 1];
            socket.read_exact(&mut len).await?;
            let mut domain = vec![0u8; len[0] as usize];
            socket.read_exact(&mut domain).await?;
            let mut port = [0u8; 2];
            socket.read_exact(&mut port).await?;
            format!("{}:{}", String::from_utf8_lossy(&domain), u16::from_be_bytes(port))
        }
        _ => {
            // Reply: address type not supported
            socket.write_all(&[0x05, 0x08, 0x00, 0x01, 0, 0, 0, 0, 0, 0]).await?;
            return Ok(());
        }
    };

    debug!("SOCKS5 request: cmd={}, addr={}", cmd, addr);

    if cmd != 0x01 {
        // Only support CONNECT
        socket.write_all(&[0x05, 0x07, 0x00, 0x01, 0, 0, 0, 0, 0, 0]).await?;
        return Ok(());
    }

    // Connect to target (simplified - should go through Hysteria server)
    match TcpStream::connect(&addr).await {
        Ok(mut target) => {
            // Reply: success
            socket.write_all(&[0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0]).await?;

            // Relay data
            let (mut client_read, mut client_write) = socket.split();
            let (mut target_read, mut target_write) = target.split();

            let client_to_target = async {
                tokio::io::copy(&mut client_read, &mut target_write).await
            };

            let target_to_client = async {
                tokio::io::copy(&mut target_read, &mut client_write).await
            };

            tokio::try_join!(client_to_target, target_to_client)?;
        }
        Err(_) => {
            // Reply: connection refused
            socket.write_all(&[0x05, 0x05, 0x00, 0x01, 0, 0, 0, 0, 0, 0]).await?;
        }
    }

    Ok(())
}
